package com.ggb.reactive.controller.user

import com.ggb.reactive.constant.ACTION_FAIL
import com.ggb.reactive.constant.DEFAULT_ADDRESS_NOT_FIND
import com.ggb.reactive.constant.ENABLE
import com.ggb.reactive.constant.USER_ID
import com.ggb.reactive.domain.entity.AddressBook
import com.ggb.reactive.extension.log
import com.ggb.reactive.model.Result
import com.ggb.reactive.repository.AddressBookRepository
import com.ggb.reactive.service.AddressBookService
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import lombok.RequiredArgsConstructor
import org.springframework.beans.BeanUtils
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.switchIfEmpty

@RequestMapping("/user/addressBook")
@RestController
@RequiredArgsConstructor
@Tag(name = "用户地址模块")
class AddressBookController(
    val addressBookRepository: AddressBookRepository,
    val addressBookService: AddressBookService
) {
    @GetMapping("/list")
    @Operation(summary = "查询当前登录用户的所有地址信息")
    fun list(exchange: ServerWebExchange): Mono<Result<List<AddressBook>>> {
        val userId = (exchange.attributes[USER_ID] as Int).toLong()
        return addressBookRepository.findAllByUserId(userId)
            .collectList().map {
                Result.success(it)
            }
    }

    @PostMapping
    @Operation(summary = "新增地址")
    fun save(@RequestBody addressBook: AddressBook,exchange: ServerWebExchange): Mono<Result<String>> {
        val address = AddressBook()
        val userId = (exchange.attributes[USER_ID] as Int).toLong()
        BeanUtils.copyProperties(addressBook,address)
        address.userId = userId
        return addressBookRepository.save(address)
            .map {
                Result.success()
            }
    }

    @GetMapping("/{id}")
    @Operation(summary = "根据id查询地址")
    fun getById(@PathVariable id: Long): Mono<Result<AddressBook>> {
        return addressBookRepository.findById(id)
            .map {
                Result.success(it)
            }
    }

    @PutMapping
    @Operation(summary = "更新地址")
    fun update(@RequestBody addressBook: AddressBook): Mono<Result<String>> {

        return addressBookService.update(addressBook)
            .map {
                Result.success()
            }
    }

    @PutMapping("/default")
    @Operation(summary = "设置默认地址")
    @Transactional
    fun setDefault(@RequestBody addressBook: AddressBook, exchange: ServerWebExchange): Mono<Result<String>> {
        val userId = (exchange.attributes[USER_ID] as Int).toLong()
        return addressBookRepository.setNotDefaultByUserId(userId).flatMap {
            addressBookRepository.updateIsDefaultById(ENABLE, addressBook.id!!)
        }.map {
            Result.success()
        }
    }

    @DeleteMapping("/")
    @Operation(summary = "根据id删除地址")
    fun deleteById(@RequestParam id: Long): Mono<Result<String>> {
        return addressBookRepository.deleteById(id)
            .then(Mono.just(Result.success<String>()))
            .onErrorResume {
                Mono.just(Result.error(ACTION_FAIL))
            }
    }

    @GetMapping("/default")
    @Operation(summary = "查询默认地址")
    fun getDefault(exchange: ServerWebExchange): Mono<Result<AddressBook?>> {
        val userId = (exchange.attributes[USER_ID] as Int).toLong()
        return addressBookRepository.findByUserIdAndIsDefault(userId, 1)
            .mapNotNull {
                Result.success(it)
            }
            .switchIfEmpty {
                Mono.just(Result.error(DEFAULT_ADDRESS_NOT_FIND))
            }
    }
}